package su.fishr.effects.flySquares 
{
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import su.fishr.effects.flySquares.CuttingFragments;
	
	
	/** 
	 *  Модель приложения.
	 *  - в фазе подготовки создает копию входящего ДО, передает в виевер,
	 *  - нарезает на фрагменты BitmapData DisplayObject-а,
	 *  - в ходе работы по запросу контролла готовит очередной фрагмент, сообщает
	 *    о готовности его к выводу на сцену.
	 *  - по окончании работы уничтожает все оставшиеся фрагменты.
	 * @author fish_r
	 */
	internal class MFlySquares extends EventDispatcher 
	{
		
	/**-------------------------------------------------------------------------------
	* 
	* 	
	* 
	*					V A R I A B L E ' S  	
	*
	* 
	* 
	* --------------------------------------------------------------------------------
	*/
		public const ADD_FRAGMENT:String = "Add Fragment";
		public const SELECT_SIZE:String = "selectSize";
		public const END_COLOUMN:String = "endColoumn";
		
		
		
		private var _dObject:Bitmap;
		private var _dataObject:BitmapData;
		private var _sizeFragment:uint;
		private var _addFragment:Array;
		private var _arrFragments:Array;
		private var _addColoumn:int;
		private var _lastFr:Array = new Array();
		private var _vertical:Boolean;
		private var _rectShift:Rectangle;
		private var _countFr:uint;
		private var _distance:uint;
		private var _bomb:Boolean = false;
		
		
	/**-------------------------------------------------------------------------------
	* 
	* 	
	* 
	*					P R O P E R T I E S 	
	*
	* 
	* 
	* --------------------------------------------------------------------------------
	*/
		public function get numSectors():uint 
		{
			return _sizeFragment;
		}
		public function set numSectors(value:uint):void 
		{
			if ( _sizeFragment === value ) return;
			_sizeFragment = value;
		}
		
		
		
		public function get addFragment():Array { return _addFragment[0]; }
		
		public function set addColoumn(value:int):void 
		{
			_addColoumn = value;
			///TODO Заплатка от неожиданного удаления.
			if ( _arrFragments )upFragments();
			
		}
		
		public function get dObject():Bitmap
		{
			return _dObject;
		}

		public function get lastFr():Array
		{
			return _lastFr;
		}
		
		public function set lastFr(value:Array):void 
		{
			_lastFr = value;
		}
		
		public function set vertical(value:Boolean):void 
		{
			_vertical = value;
		}
		
		public function get countFr():uint
		{
			return _countFr;
		}
		
		/**
		 *  Хранит смещение объекта относительно
		 * внутренней системы координат. Актуально
		 * для переданных объектов с измененной
		 * матрицей.
		 */
		public function get rectShift():Rectangle 
		{
			return _rectShift;
		}
		
		
		/**
		 *  Массив всех фрагментов исходного
		 * объекта.
		 */
		public function get arrFragments():Array 
		{
			return _arrFragments;
		}
		
		public function set bomb(value:Boolean):void 
		{
			_bomb = value;
		}
		
	/**-------------------------------------------------------------------------------
	* 
	* 	
	* 
	*				C O N S T R U C T O R 	
	*
	* 
	* 
	* --------------------------------------------------------------------------------
	*/
		
		public function MFlySquares(obj:DisplayObject, distance:uint, shift:Rectangle, target:IEventDispatcher = null) 
		{
			_rectShift = shift;
			createBitmap(obj);
			_distance = distance;
			super(target);
			
		}
	/**-------------------------------------------------------------------------------
	* 
	* 	
	* 
	*					P U B L I C ' S  	
	*
	* 
	* 
	* --------------------------------------------------------------------------------
	*/
		public function init():void
		{

			var cuttFr:Array;
			
			_dObject.x += _rectShift.x;
			_dObject.y += _rectShift.y;
			
			if ( _vertical === true ) cuttFr = CuttingFragments.CreationVerticalArray(_dataObject, _sizeFragment, _distance, _rectShift, _bomb);
			else cuttFr = CuttingFragments.CreationArray(_dataObject, _sizeFragment, _distance, _rectShift, _bomb);
			
			_arrFragments = cuttFr[0];
			_countFr = cuttFr[1];
			_sizeFragment = _arrFragments.length;
			
			dispatchEvent ( new Event (SELECT_SIZE) );
		
		}
		

		public function disposeAll():void
		{
			_dObject.addEventListener(Event.ENTER_FRAME, disposeGroupListener);
		}
		
		private function disposeGroupListener(e:Event):void 
		{
			if (! _arrFragments ) return;
			var arr:Array;
			var fragment:Bitmap;
			
			for ( var i:int = 100; i > 0; i-- )
			{
				if ( _arrFragments.length === 0 )
				{
					_dObject.removeEventListener(Event.ENTER_FRAME, disposeGroupListener);
					_arrFragments = null;
					
					break;
				}
				arr = _arrFragments[0].shift();
				fragment = Bitmap(arr[3]);
				fragment.bitmapData.dispose();
				fragment.bitmapData = null;
				fragment = null;
				_arrFragments.shift();
				
				
			}
		}
		
	/**-------------------------------------------------------------------------------
	* 
	* 	
	* 
	*					P R I V A T E ' S  	
	*
	* 
	* 
	* --------------------------------------------------------------------------------
	*/
		
		private function createBitmap(obj:DisplayObject):void
		{
			var rectShift:Rectangle = selectPosition(obj);

			_dataObject = new BitmapData( obj.width, obj.height, true, 0x00 );
			var matrix:Matrix = new Matrix(obj.transform.matrix.a, 
											obj.transform.matrix.b,
											obj.transform.matrix.c,
											obj.transform.matrix.d,
											obj.transform.matrix.tx - obj.x - rectShift.x,
											obj.transform.matrix.ty - obj.y - rectShift.y);
			_dataObject.draw( obj , matrix, obj.transform.colorTransform );
			
			if ( !_rectShift ) _rectShift = rectShift;
			_dObject = new Bitmap(_dataObject);
		}
		
		private function upFragments():void
		{
			
			
			var coloumn:Array;
			try
			{
				for ( var i:int; i < _addColoumn; i++ )
				{
					coloumn = _arrFragments.shift();
					hashElements( coloumn );
				}
				
				

			}
			catch (e:Error)
			{
					throw(e);
				
			}
			
			
			
		}
		
		private function hashElements(arr:Array):void
		{
			var nm:int;

			while( arr.length > 0 ) 
			{
				nm = Math.random() * (arr.length );
				_addFragment = arr.splice(nm, 1);
				
				dispatchEvent(new Event(ADD_FRAGMENT));
				
			}
			
			_lastFr.push(_addFragment[0][3]);
			
			dispatchEvent( new Event( END_COLOUMN ));
		}
		
		private function selectPosition(obj:DisplayObject):Rectangle
		{
			var sp:Sprite = new Sprite();
			var rect:Rectangle;
			var childIndex:uint;
			
			
			if ( obj.parent !== null)
			{
				childIndex = obj.parent.getChildIndex(obj);
				obj.parent.addChildAt(sp, childIndex);
				sp.x = obj.x;
				sp.y = obj.y;
				sp.addChild(obj);
				rect = obj.getBounds(sp);
				rect.x -= obj.x;
				rect.y -= obj.y;
				sp.parent.addChildAt(obj, childIndex);
				obj.x = sp.x;
				obj.y = sp.y;
				obj.parent.removeChild(sp);
				sp = null;
				
			}
			else
			{
				sp.addChild(obj);
				rect = obj.getBounds(sp);
				rect.x -= obj.x;
				rect.y -= obj.y;
				sp.removeChild(obj);
				sp = null;
				
				
			}
			
			return rect;
			
		}
		
		
		
		
		
	}

}